package com.xmh.myutil.util;

import lombok.extern.log4j.Log4j;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Log4j
public class CageTest {

    private final Map<String, String> headerChangeMap = Config.getHeaderChangeMap();

    private final String path = Config.getPath();

    private final String startBrackets = "く";

    private final String endBrackets = "う";

    @Test
    public void teest1() {
        ArrayList<String> fileNameList = new ArrayList<>();

        getAllFileName(path, fileNameList);

        for (String fileName : fileNameList) {
            String javaFilePath = path + "\\" + fileName;

            String javaCode = Objects.requireNonNull(getFileStr(javaFilePath)).replaceAll("\\(", startBrackets).replaceAll("\\)", endBrackets);

            List<String> methodList = getMethodList(javaCode);

//           for the  System.out.println();
            systemOutPrint(javaCode, methodList);

//           for the file string
            createFile(fileName, javaCode, methodList);
        }
    }

    /**
     * 创建文件
     *
     * @param fileName 文件名
     * @param javaCode java代码
     * @param methodList 方法列表
     */
    private void createFile(String fileName, String javaCode, List<String> methodList) {
        String aPackage = "package";

        String classesStringStart = aPackage + StringUtils.substringBetween(javaCode, aPackage, methodList.get(0));

        String javaCodeLastStr = javaCode.substring(javaCode.length() - 3);

        String classesStringEnd = StringUtils.substringBetween(javaCode, methodList.get(methodList.size() - 1), javaCodeLastStr) + javaCodeLastStr;

        StringBuilder classesSB = new StringBuilder(classesStringStart);
        for (String methodStr : methodList) {
            if (!methodStr.contains(" public ")) {
                classesSB.append(methodStr);
                continue;
            }

            GetParameterIndex getParameterIndex = new GetParameterIndex(startBrackets, endBrackets, methodStr).invoke();
            int startIndex = getParameterIndex.getStartIndex();
            int endIndex = getParameterIndex.getEndIndex();

            String parameterStrs = getParameterStr(methodStr, startIndex, endIndex);

            List<String> parameterList = getParameterList(parameterStrs);

            StringBuilder parameterSB = new StringBuilder();

            for (int i = 0; i < parameterList.size(); i++) {
                String parameterStr = parameterList.get(i);
                boolean isThreeParameter = false;
                for (Map.Entry<String, String> entry : Config.getHeaderToParameterMap().entrySet()) {
                    if (parameterStr.contains(entry.getKey())) {
                        String pattern = Config.getParameterToPatternMap().get(entry.getValue());

                        parameterSB.append(" @RequestParam(\"").append(entry.getValue()).append("\") ").append(pattern).append(" String ").append(entry.getValue());

                        isThreeParameter = true;
                        break;
                    }
                }
                if (!isThreeParameter) {
                    parameterSB.append(parameterStr);
                }
                if (i != parameterList.size() - 1) {
                    parameterSB.append(",");
                }
            }
            StringBuilder stringBuilder = new StringBuilder(methodStr);

            String parameterString = parameterSB.toString();

            String replace1;
            if (parameterString.startsWith("@")) {
                replace1 = "\n        @" + parameterString.substring(1).replace("@", "\n        @");
            } else {
                replace1 = "\n        " + parameterString.replace("@", "\n        @");
            }

            StringBuilder replace = stringBuilder.replace(startIndex, endIndex, replace1);
            classesSB.append(replace);
        }
        classesSB.append(classesStringEnd);
        String x = classesSB.toString().replaceAll(startBrackets, "\\(").replaceAll(endBrackets, "\\)");
        outFile(x, path + "\\test\\" + fileName);
    }

    /**
     * 输出信息
     *
     * @param javaCode java 代码
     * @param methodList 方法列表
     */
    private void systemOutPrint(String javaCode, List<String> methodList) {
        for (String methodStr : methodList) {

            if (!methodStr.contains(" public ")) {
                continue;
            }

            GetParameterIndex getParameterIndex = new GetParameterIndex(startBrackets, endBrackets, methodStr).invoke();
            int startIndex = getParameterIndex.getStartIndex();
            int endIndex = getParameterIndex.getEndIndex();

            String parameterStrs = getParameterStr(methodStr, startIndex, endIndex);

            List<String> parameterList = getParameterList(parameterStrs);

            String methodAnnotation = StringUtils.substringBetween(methodStr, "Mapping" + startBrackets, endBrackets);
            String urlPath = StringUtils.substringBetween(methodAnnotation, "\"", "\"");

            int annotationIndex = javaCode.indexOf(methodAnnotation);

            String modify = javaCode.substring(annotationIndex - 15, annotationIndex - 1);

            System.out.println();
            System.out.println(modify + " " + urlPath);
            parameterList.forEach(parameterStr -> {
                for (Map.Entry<String, String> entry : headerChangeMap.entrySet()) {
                    if (parameterStr.contains(entry.getKey())) {
                        System.out.println(entry.getKey() + " → " + entry.getValue());
                        break;
                    }
                }
            });
            for (String parameterStr : parameterList) {
                for (Map.Entry<String, String> entry : Config.getHeaderToParameterMap().entrySet()) {
                    if (parameterStr.contains(entry.getKey())) {
                        System.out.println("header " + entry.getKey() + " change to parameter " + entry.getValue());
                        break;
                    }
                }
            }
        }
    }

    /**
     * 从字符串中截取方法列表
     *
     * @param javaCode java代码
     * @return 方法列表
     */
    private List<String> getMethodList(String javaCode) {
        int bigBracketsCount = 0;
        int lastTimeIndex = 0;
        List<String> methodList = new ArrayList<>();

        for (int k = javaCode.indexOf("public"); k < javaCode.length(); k++) {
            String indexStr = String.valueOf(javaCode.charAt(k));

            if (indexStr.equals("{")) {
                if (lastTimeIndex == 0) {
                    lastTimeIndex = k + 1;
                }
                bigBracketsCount++;
            } else if (indexStr.equals("}")) {
                bigBracketsCount--;
                if (bigBracketsCount == 1) {
                    String substring = javaCode.substring(lastTimeIndex, k) + "}";

                    substring = getMethodAndDontHaveAnyParameter(substring);

                    String[] lastBraceList = StringUtils.substringsBetween(substring, "{", "}");
                    String braceContent = lastBraceList[lastBraceList.length - 1];

                    if (braceContent == null || braceContent.length() < 20) {
                        continue;
                    }

                    methodList.add(substring);
                    lastTimeIndex = k + 1;
                }
            }
        }
        return methodList;
    }

    private String getMethodAndDontHaveAnyParameter(String substring) {
        String open = ";";
        String close = "Mappingく";
        String str = StringUtils.substringBetween(substring, open, close);
        if (StringUtils.isNotEmpty(str)) {
            String substring1 = substring.substring(substring.length() - 10);
            substring = StringUtils.substringBetween(substring, open, substring1) + substring1;
            return getMethodAndDontHaveAnyParameter(substring);
        }
        return substring;
    }

    private String getParameterStr(String method, int startIndex, int endIndex) {
        String substring = method.substring(startIndex, endIndex);
        String replace = substring.replace("\r", "").replace("\n", "").replaceAll(" +", " ");
        return replace + endBrackets;
    }

    private List<String> getParameterList(String parameterStr) {
        List<String> list = new ArrayList<>();

        int lastTimeIndex = 0;

        int bracketsCount = 1;

        for (int j = 0; j < parameterStr.length(); j++) {
            String indexStr = String.valueOf(parameterStr.charAt(j));

            if (indexStr.equals(startBrackets)) {
                bracketsCount++;
            } else if (indexStr.equals(endBrackets)) {
                bracketsCount--;
            }

            if ((indexStr.equals(",") && bracketsCount == 1) || bracketsCount == 0) {
                String substring = parameterStr.substring(lastTimeIndex == 0 ? 0 : lastTimeIndex + 1, j);
                list.add(substring.trim());
                lastTimeIndex = j;
            }
        }
        return list;
    }

    private void outFile(String data, String path) {
        try {
            File file = new File(path);

            if (!file.exists()) {
                file.createNewFile();
            }
            PrintWriter out = new PrintWriter(new FileWriter(file));

            out.write(data);
            out.flush();
            out.close();
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 获取某个文件夹下的所有文件
     *
     * @param fileNameList 存放文件名称的list
     * @param path         文件夹的路径
     */
    public static void getAllFileName(String path, ArrayList<String> fileNameList) {
        //ArrayList<String> files = new ArrayList<String>();
        File file = new File(path);
        File[] tempList = file.listFiles();

        for (int i = 0; i < Objects.requireNonNull(tempList).length; i++) {
            if (tempList[i].isFile()) {
//              System.out.println("文     件：" + tempList[i]);
                //fileNameList.add(tempList[i].toString());
                fileNameList.add(tempList[i].getName());
            }
            if (tempList[i].isDirectory()) {
//              System.out.println("文件夹：" + tempList[i]);
                getAllFileName(tempList[i].getAbsolutePath(), fileNameList);
            }
        }
    }

    private String getFileStr(String path) {
        File file = new File(path);

        Reader in = null;

        String string;
        FileInputStream in2 = null;
        try {
            in2 = new FileInputStream(file);
            in = new InputStreamReader(in2, StandardCharsets.UTF_8);
            StringBuilder sBuffer = new StringBuilder();

            int len;
            while ((len = in.read()) != -1) {
                sBuffer.append((char) len);
            }
            in.close();
            string = sBuffer.toString();
        } catch (IOException e) {
            log.error("", e);
            return null;
        } finally {
            try {
                if (in2 != null) {
                    in2.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                log.error("", e);
            }
        }
        return string;
    }


    private static class GetParameterIndex {
        private final String startBrackets;
        private final String endBrackets;
        private final String methodStr;
        private int startIndex;
        private int endIndex;

        public GetParameterIndex(String startBrackets, String endBrackets, String methodStr) {
            this.startBrackets = startBrackets;
            this.endBrackets = endBrackets;
            this.methodStr = methodStr;
        }

        public int getStartIndex() {
            return startIndex;
        }

        public int getEndIndex() {
            return endIndex;
        }

        public GetParameterIndex invoke() {
            startIndex = 0;
            endIndex = 0;

            int bracketsCount = 0;

            for (int i = methodStr.indexOf("public"); i < methodStr.length(); i++) {
                String indexStr = String.valueOf(methodStr.charAt(i));
                if (indexStr.equals(startBrackets)) {
//                    开始的第一个（括号的下标位置
                    if (startIndex == 0) {
                        startIndex = i + 1;
                    }
                    bracketsCount++;
                } else if (indexStr.equals(endBrackets)) {
                    if (--bracketsCount == 0) {
                        endIndex = i;
                        break;
                    }
                }
            }
            return this;
        }
    }
}
